#include "../include/mergeToVx.h"
#include "../include/busapi.h"
#include <stdlib.h>
#include <stdio.h>
#include <taskLib.h>


#define MY_CARD_TYPE	 CPCI1553
#define MY_INSTANCE		 1

int					ch_id[2];
API_INT_FIFO		g_sIntFIFO[2];
API_RT_ABUF			Abuf;	// RT address buffer structure.
API_RT_CBUF			Cbuf; 	// RT control buffer structures.
API_RT_MBUF_WRITE	msg_buffer_write;
int nCurrentRT;

BT_INT _stdcall MyBC_event_handlerBC(BT_UINT cardnum, struct api_int_fifo *pFIFO);
BT_INT _stdcall MyRt_event_handlerRT(BT_UINT cardnum, struct api_int_fifo *pFIFO);

//frame 1: 10ms, rt1 - rt10
//frame 2: 20ms, rt11 - rt15
//CH1 simulate RT1 -- RT6

void AperiodMsgProc(void);
void RTChangeThreadProc(void);

int g_nBCMsgCnt = 0, nRTMsgCnt = 0;
int	nQuitAperiod = 1, nQuitRTChange = 1;

void MyMain(void) 
{
	char  			c;
	API_BC_MBUF		bc_msg[20];
	BT_INT			status;	
	API_BC_MBUF		bc_msg_rc[2];
	int				i, dev_num, mode, rt, sub;

	printf("Initializing API with BusTools_API_OpenChannel . . . \n");

    // First find the device based on type and instance.
   	dev_num = BusTools_FindDevice(MY_CARD_TYPE, MY_INSTANCE);
   	if (dev_num < 0) printf("ERROR IN BUSTOOLS_FINDDEVICE.\n");

   	// Open the device and get the channel id.
   	mode = API_B_MODE | API_SW_INTERRUPT;  // 1553B protocol, use SW interrupts.
   	status = BusTools_API_OpenChannel(&ch_id[0], mode, dev_num, 0);

	if (status == API_SUCCESS) 
	{
		printf("Open CH0 Success.\n");

		status = BusTools_API_OpenChannel(&ch_id[1], mode, dev_num, 1);
		if(status == API_SUCCESS)
		{
			printf("Open CH1 Success.\n");

			status = BusTools_RT_Init(ch_id[1], 0);
			if (status == API_SUCCESS) 
			{
				nCurrentRT = 1;

				//enable RT1
				Abuf.enable_a = 1;			// Respond on bus A
				Abuf.enable_b = 1;			// Respond on bus B
				Abuf.inhibit_term_flag = 1;	// Inhibit terminal flag in status word
				Abuf.status = (1 << 11);	// Set status word
				Abuf.bit_word = 0x0000;		// Set BIT word (for mode code 19)
				
				status = BusTools_RT_AbufWrite(ch_id[1], nCurrentRT, &Abuf);
				if (status != API_SUCCESS)
				{
					printf("Error %d on BusTools_RT_AbufWrite.\n", status);	
				} 

				Cbuf.legal_wordcount = 0xFFFFFFFF;
				msg_buffer_write.enable = BT1553_INT_END_OF_MESS;	// Int on msg complete
				msg_buffer_write.error_inj_id = 0;					// No error injection

				// Setup RT address buffer
				for(rt = 1; rt < 7; rt++)
				{	
					sub = rt;	
					
					BusTools_RT_CbufWrite(ch_id[1], rt, sub, (rt % 2), 1, &Cbuf);
					for (i = 0; i < 32; i++)
					{
						msg_buffer_write.mess_data[i] = (rt << 8) + i;
					}
						
					BusTools_RT_MessageWrite(ch_id[1], rt, sub, (rt % 2), 0, &msg_buffer_write);
				}
				
				// Setup for our interrupt event handling functions
				memset(&g_sIntFIFO[1], 0, sizeof(g_sIntFIFO[1]));
				g_sIntFIFO[1].function       = MyRt_event_handlerRT;
				g_sIntFIFO[1].iPriority      = THREAD_PRIORITY_BELOW_NORMAL;
				g_sIntFIFO[1].dwMilliseconds = INFINITE;
				g_sIntFIFO[1].iNotification  = 0;

				// Register for RT message events
				g_sIntFIFO[1].FilterType     = EVENT_RT_MESSAGE;
				for(rt = 1; rt < 7; rt++)
				{
            			g_sIntFIFO[1].FilterMask[rt][rt % 2][rt] = 0xFFFFFFFF;  // Enable all messages,rt = sub
				}
				// Call the register function to register and start the thread.
				printf("Registering RT event handler . . . \n");
				status = BusTools_RegisterFunction(ch_id[1], &g_sIntFIFO[1], REGISTER_FUNCTION);
				if (status != API_SUCCESS) printf("Error = %d.\n", status);
				else printf("Success.\n");

				// Now lets turn on our RT 
				status = BusTools_RT_StartStop(ch_id[1], 1);
				printf("RT is running\n");
			}			
		}
		else
		{
			printf("Open CH1 Failed.Press any key to exit\n");
			scanf("%c", &c);
			return;
		}

		// Now lets set up a simple BC.
		// Initialize BC for interrupts, no retries, no resp at 14us, late resp at 12us,
		// minor frame time of 50000us, 2 data buffers per message.
		printf("BC Init . . . \n");
		status = BusTools_BC_Init(ch_id[0], 0, BT1553_INT_END_OF_MESS, 0, 14, 12, 10000, 2);
		if (status != API_SUCCESS) 
		{
			printf("ERROR = %d\n",status);	
		}
		else 
		{
			// Allocate memory on the board for 10 message blocks.
			BusTools_BC_MessageAlloc(ch_id[0], 10);
		
			//10ms List1, msgno: 0 - 14
			for(rt = 1; rt < 16; rt++)
			{
				printf("MSG %d . . . \n", rt - 1);
				bc_msg[rt-1].messno				= rt - 1;			// Message number
				bc_msg[rt-1].control = BC_CONTROL_MESSAGE;			// This is a standard BC message.
				bc_msg[rt-1].control |= BC_CONTROL_CHANNELA;		// Send message on bus A (primary).
				bc_msg[rt-1].control |= BC_CONTROL_BUFFERA;			// Using buffer A
				bc_msg[rt-1].messno_next	= rt;					// Next message number
				if(rt == 1)
				{
					bc_msg[rt-1].control |= BC_CONTROL_MFRAME_BEG;	// Beginning of minor frame.
				}
				else if(rt == 15)
				{
					bc_msg[rt-1].control |= BC_CONTROL_MFRAME_END;	
					bc_msg[rt-1].messno_next	= rt;				//Point to the next frame
				}
		
				bc_msg[rt-1].control |= BC_CONTROL_INTERRUPT;		// ENABLE INTERRUPT ON THIS MESSAGE.		
				bc_msg[rt-1].mess_command1.rtaddr	= rt;			// Command word 1, RT address
				bc_msg[rt-1].mess_command1.subaddr = rt;			// Command word 1, Subaddress
				bc_msg[rt-1].mess_command1.tran_rec = (rt % 2);		// Command word 1, transmit (1) or receive (0)
				bc_msg[rt-1].mess_command1.wcount	= rt+5;			// Command word 1, word count, 0-31, 0=32 words
				bc_msg[rt-1].mess_command2.rtaddr	= 0;			// Command word 2, RT address		
				bc_msg[rt-1].mess_command2.subaddr 	= 0;			// Command word 2, Subaddress
				bc_msg[rt-1].mess_command2.tran_rec = 0;			// Command word 2, transmit (1) or receive (0)
				bc_msg[rt-1].mess_command2.wcount	= 0;			// Command word 2, word count, 0-31, 0=32 words
				bc_msg[rt-1].errorid			= 0;			// Error injection buffer ID, no err inj
				bc_msg[rt-1].gap_time			= 10;			// Intermessage gap time in microseconds
				bc_msg[rt-1].status				= 0;			// Returned from HW	

				// Initialize active data
				for (i=0; i<32; i++) bc_msg[rt-1].data[0][i] = (rt << 12) + i;		
				BusTools_BC_MessageWrite(ch_id[0], (rt - 1), &bc_msg[rt-1]);	
			}	

			//10ms List2, msgno: 15 - 24
			for (rt = 1; rt < 11; rt++)
			{
				printf("MSG %d . . . \n", rt + 14);
				bc_msg[rt-1].messno				= rt + 14;			// Message number
				bc_msg[rt-1].control = BC_CONTROL_MESSAGE;			// This is a standard BC message.
				bc_msg[rt-1].control |= BC_CONTROL_CHANNELA;		// Send message on bus A (primary).
				bc_msg[rt-1].control |= BC_CONTROL_BUFFERA;			// Using buffer A
				bc_msg[rt-1].messno_next	= rt + 15;				// Next message number
				if(rt == 1)
				{
					bc_msg[rt-1].control |= BC_CONTROL_MFRAME_BEG;	// Beginning of minor frame.
				}
				else if(rt == 10)
				{
					bc_msg[rt-1].control |= BC_CONTROL_MFRAME_END;
					bc_msg[rt-1].messno_next	= 0;
				}
				
				bc_msg[rt-1].control |= BC_CONTROL_INTERRUPT;		// ENABLE INTERRUPT ON THIS MESSAGE.		
				bc_msg[rt-1].mess_command1.rtaddr	= rt;			// Command word 1, RT address
				bc_msg[rt-1].mess_command1.subaddr = rt;			// Command word 1, Subaddress
				bc_msg[rt-1].mess_command1.tran_rec = (rt % 2);		// Command word 1, transmit (1) or receive (0)
				bc_msg[rt-1].mess_command1.wcount	= rt+5;			// Command word 1, word count, 0-31, 0=32 words
				bc_msg[rt-1].mess_command2.rtaddr	= 0;			// Command word 2, RT address		
				bc_msg[rt-1].mess_command2.subaddr 	= 0;			// Command word 2, Subaddress
				bc_msg[rt-1].mess_command2.tran_rec = 0;			// Command word 2, transmit (1) or receive (0)
				bc_msg[rt-1].mess_command2.wcount	= 0;			// Command word 2, word count, 0-31, 0=32 words
				bc_msg[rt-1].errorid			= 0;			// Error injection buffer ID, no err inj
				bc_msg[rt-1].gap_time			= 10;			// Intermessage gap time in microseconds
				bc_msg[rt-1].status				= 0;			// Returned from HW	
				
				// Initialize active data
				for (i=0; i<32; i++) bc_msg[rt-1].data[0][i] = (rt << 12) + i;		
				BusTools_BC_MessageWrite(ch_id[0], (rt + 14), &bc_msg[rt-1]);	
			}

			//Aperiod message list, msgno: 25 - 29
			for (rt = 16; rt < 21; rt++)
			{
				printf("MSG %d . . . \n", rt + 9);
				bc_msg[rt-1].messno				= rt + 9;			// Message number
				bc_msg[rt-1].control = BC_CONTROL_MESSAGE;			// This is a standard BC message.
				bc_msg[rt-1].control |= BC_CONTROL_CHANNELA;		// Send message on bus A (primary).
				bc_msg[rt-1].control |= BC_CONTROL_BUFFERA;			// Using buffer A
				bc_msg[rt-1].messno_next	= rt + 10;					// Next message number				
				if(rt == 20)
				{
					bc_msg[rt-1].messno_next	= 0xffff;
				}
				
				bc_msg[rt-1].control |= BC_CONTROL_INTERRUPT;		// ENABLE INTERRUPT ON THIS MESSAGE.		
				bc_msg[rt-1].mess_command1.rtaddr	= rt;			// Command word 1, RT address
				bc_msg[rt-1].mess_command1.subaddr  = rt;			// Command word 1, Subaddress
				bc_msg[rt-1].mess_command1.tran_rec = (rt % 2);		// Command word 1, transmit (1) or receive (0)
				bc_msg[rt-1].mess_command1.wcount	= rt+5;			// Command word 1, word count, 0-31, 0=32 words
				bc_msg[rt-1].errorid			= 0;			// Error injection buffer ID, no err inj
				bc_msg[rt-1].gap_time			= 10;			// Intermessage gap time in microseconds
				bc_msg[rt-1].status				= 0;			// Returned from HW	
				
				// Initialize active data
				for (i=0; i < 32; i++) 
				{
					bc_msg[rt-1].data[0][i] = (rt << 12) + i;	
				}		
				
				BusTools_BC_MessageWrite(ch_id[0], (rt + 9), &bc_msg[rt-1]);	
			}

			// Setup for our interrupt event handling functions
			memset(&g_sIntFIFO[0], 0, sizeof(g_sIntFIFO[0]));
			g_sIntFIFO[0].function       = MyBC_event_handlerBC;
			g_sIntFIFO[0].iPriority      = THREAD_PRIORITY_BELOW_NORMAL;
			g_sIntFIFO[0].dwMilliseconds = INFINITE;
			g_sIntFIFO[0].iNotification  = 0;

			// Register for BC message events
			g_sIntFIFO[0].FilterType     = EVENT_BC_MESSAGE;
			for(rt = 1; rt < 21; rt++)
			{
				g_sIntFIFO[0].FilterMask[rt][rt%2][rt] = 0xFFFFFFFF;
           	}

			// Call the register function to register and start the thread.
			printf("Registering BC event handler . . . \n");
			status = BusTools_RegisterFunction(ch_id[0], &g_sIntFIFO[0], REGISTER_FUNCTION);
			if (status != API_SUCCESS)
			{
				printf("Error = %d.\n", status);
			} 
			else
			{
				printf("Success.\n");	
			}
			// Start the bus controller, will start list at msg #0.
			printf("Press any key to start BC . . . \n");
			scanf("%c", &c);
			status = BusTools_BC_StartStop(ch_id[0], 1);
			if (status != API_SUCCESS)
			{
				printf("ERROR = %d\n",status);
			} 
			
			printf("Set timer\n");

			if (NULL == taskSpawn("BCAperiodOpr",100,0,10000,(FUNCPTR)AperiodMsgProc,0,0,0,0,0,0,0,0,0,0))
			{
				printf("Aperiod task BCAperiodOpr is error!\n");
			}
			
			if (NULL == taskSpawn("RTChangeThread",100,0,10000,(FUNCPTR)RTChangeThreadProc,0,0,0,0,0,0,0,0,0,0))
			{
				printf("RTChange task RTChangeThread is error!\n");
			}
		
			do
     		{
				printf("Input Q to stop and exit, anything else to get messge count.\n");
				scanf("%c",&c);
				
				if (c != 'Q')
				{	
					status = BusTools_BC_MessageRead(ch_id[0], 26, &bc_msg_rc[1]);
					if (status == API_SUCCESS) 
					{
						for(i = 0; i < 32; i++)
						{
							printf("%04x ",bc_msg_rc[1].data[0][i]);
							if (!((i+1)%8))
							{
								printf("\n");	
							}
						}
					}
					
					printf("BC message count = %d, RT message count = %d\n", g_nBCMsgCnt, nRTMsgCnt);  
				} // End of if (c != 'Q')
      		} while (c != 'Q'); // End of do-while

			// Stop the BC.
			printf("BC stopping  \n");
			status = BusTools_BC_StartStop(ch_id[0], 0);
			if (status != API_SUCCESS) 
			{
				printf("Error = %d.\n", status);	
			}
			else
			{
				printf("Stopped.\n");
			} 

			printf("Kill timer . . . \n");		

			nQuitAperiod = 0;
			nQuitRTChange = 0;	
			taskDelay(20);

			
			printf("Unregistering BC event handler\n");
			status = BusTools_RegisterFunction(ch_id[0], &g_sIntFIFO[0], UNREGISTER_FUNCTION);
			BusTools_API_Close(ch_id[0]);			

			printf("RT stopping\n");
			status = BusTools_RT_StartStop(ch_id[1], 0);
			if (status != API_SUCCESS)
			{
				printf("Error = %d.\n", status);	
			}
			else
			{
				printf("Stopped.\n");
			} 

			printf("Unregistering RT event handler\n");
			status = BusTools_RegisterFunction(ch_id[1], &g_sIntFIFO[1], UNREGISTER_FUNCTION);
			
			BusTools_API_Close(ch_id[1]);	
			printf("BC message count = %d, RT message count = %d\n", g_nBCMsgCnt, nRTMsgCnt);
		}

	} // End of if (initialization successful)
	else 
	{
		printf("FAILURE, error = %d\n", status);	
	}

	printf("FINISHED.\n");
} // End of main


BT_INT _stdcall MyBC_event_handlerBC(BT_UINT cardnum, struct api_int_fifo *g_sIntFIFO)
{
   BT_INT				tail;	           // FIFO Tail index
   API_BC_MBUF			bc_msg;

   // Loop through all entries in the FIFO
   // Fetch entries from the FIFO: Get the tail pointer and extract the entry
   // it points to.   When (head == tail) then FIFO is empty.
   tail = g_sIntFIFO->tail_index;
   while ( tail != g_sIntFIFO->head_index )
   {
      if ( g_sIntFIFO->fifo[tail].event_type & EVENT_BC_MESSAGE )
      {
         //  Process a BC interrupt:
         //g_sIntFIFO->fifo[tail].buffer_off       // Byte address of buffer
         //g_sIntFIFO->fifo[tail].rtaddress        // RT address
         //g_sIntFIFO->fifo[tail].transrec         // Transmit/Receive
         //g_sIntFIFO->fifo[tail].subaddress       // Subaddress number
         //g_sIntFIFO->fifo[tail].wordcount        // Word count
         //g_sIntFIFO->fifo[tail].bufferID         // BC message number

		BusTools_BC_MessageRead(ch_id[0], g_sIntFIFO->fifo[tail].bufferID, &bc_msg);
		g_nBCMsgCnt++;	
      }
      // Now update and store the tail pointer.
      tail++;                         // Next entry
      tail &= g_sIntFIFO->mask_index;   // Wrap the index
      g_sIntFIFO->tail_index = tail;    // Save the index
   }
   return( API_SUCCESS );
}


BT_INT _stdcall MyRt_event_handlerRT(BT_UINT cardnum, struct api_int_fifo *g_sIntFIFO)
{
   BT_INT				tail;	           // FIFO Tail index
   API_RT_MBUF_READ		msg_buffer_read;

   tail = g_sIntFIFO->tail_index;
   while ( tail != g_sIntFIFO->head_index )
   {
      if ( g_sIntFIFO->fifo[tail].event_type & EVENT_RT_MESSAGE )
      {
          //  Process a RT interrupt:
          //g_sIntFIFO->fifo[tail].buffer_off       // Byte address of buffer
          //g_sIntFIFO->fifo[tail].rtaddress        // RT address
          //g_sIntFIFO->fifo[tail].transrec         // Transmit/Receive
          //g_sIntFIFO->fifo[tail].subaddress       // Subaddress number
          //g_sIntFIFO->fifo[tail].wordcount        // Word count
          //g_sIntFIFO->fifo[tail].bufferID         // RT message number

		BusTools_RT_MessageRead(ch_id[1],
						g_sIntFIFO->fifo[tail].rtaddress,
						g_sIntFIFO->fifo[tail].subaddress, 
						g_sIntFIFO->fifo[tail].transrec, 
						g_sIntFIFO->fifo[tail].bufferID, 
						&msg_buffer_read);
		nRTMsgCnt++;			
      }
      // Now update and store the tail pointer.
      tail++;                         // Next entry
      tail &= g_sIntFIFO->mask_index;   // Wrap the index
      g_sIntFIFO->tail_index = tail;    // Save the index
   }
   return( API_SUCCESS );
}


void AperiodMsgProc(void)
{
	while(nQuitAperiod)
	{		
		while (BusTools_BC_AperiodicTest(ch_id[0], 0) == API_BC_APERIODIC_RUNNING);						
		BusTools_BC_AperiodicRun(ch_id[0], 25, 0, 1, 20);	
		taskDelay(1);		
	}		
}

void RTChangeThreadProc(void)
{
	while(nQuitRTChange)
	{		
		Abuf.enable_a = 0;		
		Abuf.enable_b = 0;		
		Abuf.status = (nCurrentRT << 11);
		BusTools_RT_AbufWrite(ch_id[1], nCurrentRT, &Abuf);

		nCurrentRT++;
		if (nCurrentRT == 7)
		{
			nCurrentRT = 1;
		}
		Abuf.enable_a = 1;		
		Abuf.enable_b = 1;		
		Abuf.status = (nCurrentRT << 11);
		BusTools_RT_AbufWrite(ch_id[1], nCurrentRT, &Abuf);

		taskDelay(2);
//	printf("RTChange_proc\n");			
	}		
}
